package com.star.aries.service;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mathworks.toolbox.javabuilder.MWArray;
import com.mathworks.toolbox.javabuilder.MWCellArray;
import com.mathworks.toolbox.javabuilder.MWException;
import com.star.aries.constant.CacheTypeEnum;
import com.star.aries.constant.ErrorCodeEnum;
import com.star.aries.dao.TrainTypeDao;
import com.star.aries.domain.TrainType;
import com.star.aries.dto.res.CalculationResponseDto;
import com.star.aries.dto.res.CalculationResponseDto.CalData;
import com.star.aries.dto.res.CalculationResponseDto.CalDataSheng;
import com.star.aries.dto.res.CalculationResponseDto.CalDataYear;
import com.star.aries.dto.res.Matrix;
import com.star.aries.exception.HnServiceException;
import com.star.aries.utils.FileUtils;
import com.star.aries.utils.MemoryCacheUtil;

import calculation.ZhongNan;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CalculationService {
  @Autowired
  private TrainTypeDao trainTypeDao;
  
  private static List<MWArray> result1;
  private static List<MWArray> result2;
  private static List<MWArray> result3;
  private static List<Matrix> matrixs1;
  private static List<Matrix> matrixs2;
  private static List<Matrix> matrixs3;
  
  public static void main(String[] args) throws MWException {
    String sp = "C:/zhongnan/12/calculation/structure parameters.xlsx";
    String ap = "C:/zhongnan/12/calculation/acousticCav parameters.xlsx";
    String aa = "C:/zhongnan/12/calculation/adjacent area.xlsx";
    String p = "C:/zhongnan/12/calculation/powerinput.xlsx";
    String t = "C:/zhongnan/12/calculation/tlforyears.xlsx";
    String ts = "C:/zhongnan/12/calculation/transmissionloss.xlsx";
    
    boolean bool = FileUtils.allExists(sp, ap , aa, p, t, ts);
    if(! bool) {
      throw new HnServiceException(ErrorCodeEnum.PARAM_ERROR, "参数Excel没有放到指定目录(structure parameters.xlsx, acousticCav parameters.xlsx, adjacent area.xlsx, powerinput.xlsx, tlforyears.xlsx, transmissionloss.xlsx)");
    }
    ZhongNan alibaba = new ZhongNan();
    Object[] res = alibaba.calculation(3, sp, ap, aa, p, t, ts);
    System.out.println(res);
    MWCellArray data3 = (MWCellArray)res[2];
    result3 = data3.asList();
    Object[] arr = result3.get(0).toArray();
    matrixs3 = Stream.iterate(0, j -> j + 1).limit(arr.length - 1).map(j -> {
      double[] items = (double[]) arr[j];
      int year = Double.valueOf(items[0]).intValue();
      double value = items[1];
      return Matrix.builder()
          .year(year)
          .value(value)
          .build();
    }).collect(Collectors.toList());
    System.out.println(matrixs3);
  }
  
  private void cal(Long trainTypeId, boolean reload) {
    Object[] results = MemoryCacheUtil.get(CacheTypeEnum.train_type, trainTypeId, ! reload, a -> {
      try {
        TrainType type = trainTypeDao.getTrainType(trainTypeId);
        if(null == type) {
          throw new HnServiceException(ErrorCodeEnum.PARAM_ERROR, "车型id错误");
        }
        String sp = type.getExcelPath() + "/structure parameters.xlsx";
        String ap = type.getExcelPath() + "/acousticCav parameters.xlsx";
        String aa = type.getExcelPath() + "/adjacent area.xlsx";
        String p = type.getExcelPath() + "/powerinput.xlsx";
        String t = type.getExcelPath() + "/tlforyears.xlsx";
        String ts = type.getExcelPath() + "/transmissionloss.xlsx";
        
        boolean bool = FileUtils.allExists(sp, ap , aa, p, t, ts);
        if(! bool) {
          throw new HnServiceException(ErrorCodeEnum.PARAM_ERROR, "参数Excel没有放到指定目录(structure parameters.xlsx, acousticCav parameters.xlsx, adjacent area.xlsx, powerinput.xlsx, tlforyears.xlsx, transmissionloss.xlsx)");
        }
        ZhongNan alibaba = new ZhongNan();
        Object[] res = alibaba.calculation(3, sp, ap, aa, p, t, ts);
        return res;
      }catch (MWException | IOException e) {
        e.printStackTrace();
        log.error(e.getMessage(), e);
      }
      return null;
    }, null);
    if(null != results) {
      MWCellArray data1 = (MWCellArray)results[0];
      MWCellArray data2 = (MWCellArray)results[1];
      MWCellArray data3 = (MWCellArray)results[2];
      result1 = data1.asList();
      result2 = data2.asList();
      result3 = data3.asList();
      matrixs1 = Stream.iterate(0, i -> i + 1).limit(result1.size()).flatMap(i -> {
        Object[] arr = result1.get(i).toArray();
        double[] cols = (double[]) arr[0];
        return Stream.iterate(1, j -> j + 1).limit(arr.length - 1).flatMap(j -> {
          double[] items = (double[]) arr[j];
          String row = String.valueOf(Double.valueOf(items[0]).intValue());
          return Stream.iterate(1, k -> k + 1).limit(items.length - 1).map(k -> Matrix.builder()
              .year(i + 1)
              .row(row)
              .col(String.valueOf(Double.valueOf(cols[k]).intValue()))
              .value(items[k])
              .build());
        });
      }).collect(Collectors.toList());
      matrixs2 = Stream.iterate(0, i -> i + 1).limit(result2.size()).flatMap(i -> {
        Object[] arr = result2.get(i).toArray();
        double[] cols = (double[]) arr[0];
        return Stream.iterate(1, j -> j + 1).limit(arr.length - 1).flatMap(j -> {
          double[] items = (double[]) arr[j];
          String row = String.valueOf(Double.valueOf(items[0]).intValue());
          return Stream.iterate(1, k -> k + 1).limit(items.length - 1).map(k -> Matrix.builder()
              .year(i + 1)
              .row(row)
              .col(String.valueOf(Double.valueOf(cols[k]).intValue()))
              .value(items[k])
              .build());
        });
      }).collect(Collectors.toList());
      
      Object[] arr = result3.get(0).toArray();
      matrixs3 = Stream.iterate(0, j -> j + 1).limit(arr.length).map(j -> {
        double[] items = (double[]) arr[j];
        int year = Double.valueOf(items[0]).intValue();
        double value = items[1];
        return Matrix.builder()
            .year(year)
            .value(value)
            .build();
      }).collect(Collectors.toList());
    }
    System.out.println(matrixs1);
  }
  
  public CalculationResponseDto getCal(Long trainTypeId, Integer position, boolean reload) throws MWException {
    cal(trainTypeId, reload);
    
//    Map<String, List<Matrix>> five = matrixs2.stream().filter(m -> m.getCol().equals("5")).collect(Collectors.groupingBy(Matrix::getRow));
//    List<CalData> calDatasOfFive = five.entrySet().stream().map(entry -> {
//      List<Double> values = entry.getValue().stream().map(m -> m.getValue()).collect(Collectors.toList());
//      return CalData.builder().name(entry.getKey()).values(values).build();
//    }).collect(Collectors.toList());
    
    Map<String, CalDataSheng> calDatasOfSheng = matrixs2.stream().collect(Collectors.groupingBy(Matrix::getCol)).entrySet().stream().map(entry -> {
      List<CalData> calDatas = entry.getValue().stream().collect(Collectors.groupingBy(Matrix::getRow)).entrySet().stream().map(en -> {
        List<Double> values = en.getValue().stream().map(m -> m.getValue()).collect(Collectors.toList());
        return CalData.builder().name(en.getKey()).values(values).build();
      }).collect(Collectors.toList());
      return CalDataSheng.builder().a(entry.getKey()).calDatas(calDatas).build();
    }).collect(Collectors.toMap(CalDataSheng::getA, c -> c));
    
    Map<Integer, CalDataYear> calDataOfYear = matrixs2.stream().collect(Collectors.groupingBy(Matrix::getYear)).entrySet().stream().map(entry -> {
      List<CalData> calDatas = entry.getValue().stream().collect(Collectors.groupingBy(Matrix::getRow)).entrySet().stream().map(en -> {
        List<Double> values = en.getValue().stream().map(m -> m.getValue()).collect(Collectors.toList());
        return CalData.builder().name(en.getKey()).values(values).build();
      }).sorted((a, b) -> {
        int av = Integer.parseInt(a.getName());
        int bv = Integer.parseInt(b.getName());
        return av > bv ? 1 : -1;
      }).collect(Collectors.toList());
      return CalDataYear.builder().year(entry.getKey()).calDatas(calDatas).build();
    }).collect(Collectors.toMap(CalDataYear::getYear, c -> c));
    
    return CalculationResponseDto.builder()
        .calDataOfYear(calDataOfYear)
        .calDatasOfSheng(calDatasOfSheng)
        .matrixs(matrixs3)
        .build();
  }
}
